﻿using System;
using System.CodeDom;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using Sympol.SecondPass;

namespace Sympol
{
    public class ACompiler : ICompiler
    {
        public Que<IToken> TokenQue  = new Que<IToken>();
        public ACompiler(IInjector injector)
        {
            Injector = injector;
        }

        public class Que<T>
        {
            private List<T> lst = new List<T>();

            public void Push(IEnumerable<T> items)
            {
                lst.AddRange(items);
            }

            public void Push(T item)
            {
                lst.Add(item);
            }

            public T Pop()
            {
                var rtn = Peek();
                lst.RemoveAt(lst.Count - 1);
                return rtn;
            }

            public T Peek()
            {
                return lst[lst.Count - 1];
            }

            public bool Empty
            {
                get { return lst.Count < 1; }
            }
        }
        public IInjector Injector { get; private set; }

        public IStartable Compile(Que<IToken> tokens)
        {

            List<IExpression> values = new List<IExpression>();
            while (!TokenQue.Empty)
            {
                values.Add(Eval(GetStatement(tokens)));  
            }
            return null;
        }
        // can i find based on the value 
        public Que<IToken> GetStatement(Que<IToken> from)
        {
            var rtn = new Que<IToken>();
            var itm = from.Pop();
            //skip over the white space
            while (itm.Type == TokenType.WhiteSpace) { itm = TokenQue.Pop(); }

            if (itm.Type == TokenType.OpenCurly)
            {
                var opened = 1;
                //find the end curly
                rtn.Push(itm);
                while (opened > 0)
                {
                    itm = from.Pop();
                    switch (itm.Type)
                    {
                        case TokenType.OpenCurly:
                            opened++;
                            break;
                        case TokenType.CloseCurly:
                            opened--;
                            break;
                    }
                    rtn.Push(itm);
                }
            }
            else
            {
                rtn.Push(itm);
                itm = from.Pop();
                while (itm.Type != TokenType.Semicolon)
                {
                    rtn.Push(itm);
                    itm = from.Pop();
                }
                rtn.Push(itm);
            }
            return rtn;
        }
        public IExpression Eval(Que<IToken> tokens)
        {
            //by this point i know i have a single statment
            var itm = tokens.Peek();
            IExpression rtn = null;
            switch (itm.Type)
            {
                case TokenType.Ident:
                    rtn = EvalReference(tokens):
                    break;
                 case TokenType.OpenParen:
                    rtn = EvalFunction(tokens);
                    break;
                case TokenType.OpenCurly:
                    rtn = EvalObject(tokens);
                    break;
                case TokenType.Number:
                    rtn = EvalNumber(tokens);
                    break;
                case TokenType.String:
                    rtn = EvalString(tokens);
                    break;

            }
            return rtn;
        }
        private IExpression EvalReference(Que<IToken> tokens)
        {
            return null;
        }
        private IValue EvalFunction(Que<IToken> tokens)
        {
            return null;
        }

        private IValue EvalObject(Que<IToken> tokens)
        {
            return null;
        }

        private IValue EvalString(Que<IToken> tokens)
        {
            return null;
        }

        private IValue EvalNumber(Que<IToken> tokens)
        {
            return null;
        }


        public IStartable Compile(IEnumerable<IToken> tokens)
        {
            throw new NotImplementedException();
        }
    }

    public interface IFalseValue : IValue
    {
    }

    public interface IReference : IValue
    {
    }

    public interface ITrueValue : IValue
    {
    }

    public interface IInjector
    {
        T Instantiate<T>();
        void Register(IRegistrationScript tokenRegistrationScript);
    }

    public interface IRegistrationScript
    {
        void Register(IInjector injector);
    }
}
